

#include"mcu_os.h"




/// <summary>
/// 就绪表
/// </summary>
DList list_ready;   //
/// <summary>
/// 休眠列表
/// </summary>
DList list_sleep;   //
/// <summary>
/// 挂起列表
/// </summary>
DList list_suspend; //

/// <summary>
/// 当前运行的任务
/// </summary>
OS_TCB* currentRuning; //
/// <summary>
/// 空闲任务的任务控制块
/// </summary>
OS_TCB idle_tcb;      //


/// <summary>
/// 打印详细的任务信息
/// </summary>
/// <param name="tcb"></param>
void debug_print_TCB_msg(OS_TCB* tcb)
{
    if (tcb == NULL) {
        return;
    }
    else
    {
        TCB_MSG* msg = &(tcb->msg);
        if ((msg->machineTime_ms + CPU_Refresh_Interval_ms * 1.5f) < mcu_time_ms()) {
            //如果当前的机器时间超过20秒未更新，说明这个任务很久没有运行了。这时msg也不会更新，全部时间置为0.
            msg->timeUsed_ms = 0;
            msg->callDelay_ms = 0;
            msg->callTimes = 0;
            msg->timeUsed_msCount = 0;
            msg->callDelay_msCount = 0;
            msg->callTimesCount = 0;
        }
        printfs("\r\n  id:%4d,  priority:%4d,  timeInterval(s):%6.3f,  average delay(ms):%6.2f,  call frequency:%6.3f,  cpu rate:%6.3f,  ",
            tcb->id, tcb->priority,
            tcb->timeInterval_ms / 1000.0f, //任务间隔
            (float)msg->callDelay_ms / msg->callTimes,    //平均每次调用的延时
            msg->callTimes / ((float)CPU_Refresh_Interval_ms / 1000),			//每秒调用频率
            (float)msg->timeUsed_ms / CPU_Refresh_Interval_ms  	//计算cpu占用率
        );
    }
}

/// <summary>
/// 打印休眠表信息
/// </summary>
void debug_print_Sleep_msg()
{
    DListNode* listnode;
    printfs("\r\n list_sleep.count:%d ", list_sleep.count);
    if (list_sleep.count > 0) {
        listnode = list_sleep.head;
        while (listnode != NULL) {
            debug_print_TCB_msg(container_of(listnode, OS_TCB, node));
            listnode = listnode->next;
        }
    }
}

/// <summary>
/// 打印就绪表信息
/// </summary>
void debug_print_Ready_msg()
{
    DListNode* listnode;
    printfs("\r\n list_ready.count:%d ", list_ready.count);
    if (list_ready.count > 0) {
        listnode = list_ready.head;
        while (listnode != NULL) {
            debug_print_TCB_msg(container_of(listnode, OS_TCB, node));
            listnode = listnode->next;
        }
    }
}

/// <summary>
/// 打印阻塞表信息
/// </summary>
void debug_print_Suspend_msg()
{
    DListNode* listnode;
    printfs("\r\n list_suspend.count:%d ", list_suspend.count);
    if (list_suspend.count > 0) {
        listnode = list_suspend.head;
        while (listnode != NULL) {
            debug_print_TCB_msg(container_of(listnode, OS_TCB, node));
            listnode = listnode->next;
        }
    }
}

/// <summary>
/// 检查当前运行的任务是否异常。
/// </summary>
/// <returns>true 有异常。false 无异常</returns>
bool debug_currentRuning_iserror()
{
    if (currentRuning == NULL) {
        printfs("\r\n error!!  currentRuning is null ! ");
        return true;
    }
    else
    {
        if (currentRuning->funcPoint == NULL)
        {
            printfs("\r\n error!!  currentRuning->funcPoint is null!  currentRuning->ID:%d", currentRuning->id);
            return true;
        }
    }
    return false;
}

//


/// <summary>
/// 任务控制块优先级的比较函数
/// </summary>
/// <param name="tcbA">任务A</param>
/// <param name="tcbB">任务B</param>
/// <returns>优先级：A》B返回1；A==B返回0；A《B返回-1。</returns>
int TCB_priority_compare(OS_TCB* tcbA, OS_TCB* tcbB)
{
    if (tcbA != NULL && tcbB == NULL)return 1;
    if (tcbA == NULL && tcbB == NULL)return 0;
    if (tcbA == NULL && tcbB != NULL)return -1;

    if (tcbA->priority > tcbB->priority)return 1;
    if (tcbA->priority < tcbB->priority)return -1;
    else //优先级相同的话，看最近一次任务的使用时间。使用时间短的优先执行，这样整体系统延时才比较少。
    {
        if (tcbA->timeUsed_ms < tcbB->timeUsed_ms)return 1;
        if (tcbA->timeUsed_ms > tcbB->timeUsed_ms)return -1;
        else return 0;
    }
}
//。A先B唤醒返回1；B先A唤醒返回-1；同时返回0.

/// <summary>
/// 任务的唤醒时间比较
/// </summary>
/// <param name="tcbA">任务A</param>
/// <param name="tcbB">任务B</param>
/// <returns> 唤醒时间：A先唤醒返回1；B先唤醒返回-1；同时唤醒返回0 </returns>
int TCB_timeWakeUp_compare(OS_TCB* tcbA, OS_TCB* tcbB)
{
    if (tcbA != NULL && tcbB == NULL)return 1;
    if (tcbA == NULL && tcbB == NULL)return 0;
    if (tcbA == NULL && tcbB != NULL)return -1;

    if (tcbA->timeWakeUp_ms > tcbB->timeWakeUp_ms)return -1;
    else if (tcbA->timeWakeUp_ms < tcbB->timeWakeUp_ms)return 1;
    else return 0;
}

// list_sleep的尾结点最快被唤醒。

/// <summary>
/// list_ready的比较函数。按序插入是从小到大插入，按序插入后，list_ready的尾结点优先级最高。
/// </summary>
/// <param name="nodeA">节点A</param>
/// <param name="nodeB">节点B</param>
/// <returns>A》B返回1；A==B返回0；A《B返回-1</returns>
int list_ready_cmp(DListNode* nodeA, DListNode* nodeB)
{
    return TCB_priority_compare(container_of(nodeA, OS_TCB, node), container_of(nodeB, OS_TCB, node));
}
/// <summary>
/// list_sleep的比较函数。按序插入是从小到大插入，按序插入后，list_sleep的尾结点最先唤醒。
/// </summary>
/// <param name="nodeA">节点A</param>
/// <param name="nodeB">节点B</param>
/// <returns>A》B返回1；A==B返回0；A《B返回-1</returns>
int list_sleep_cmp(DListNode* nodeA, DListNode* nodeB)
{
    return TCB_timeWakeUp_compare(container_of(nodeA, OS_TCB, node), container_of(nodeB, OS_TCB, node));
}


/// <summary>
/// 按照优先级将新任务插入就绪表
/// </summary>
/// <param name="tcb">任务。
/// 如果tcb是默认态，直接插入就绪表。
/// 如果tcb是运行态，直接插入就绪表。
/// 如果tcb是就绪态，说明tcb已经在就绪表了，直接退出。
/// 如果tcb是挂起态，先从挂起链表中移出节点，再插入就绪表。
/// 如果tcb是休眠态，先从休眠链表中移出节点，再插入就绪表。
/// 如果tcb是终止态，直接退出。
/// </param>
/// <returns>错误码</returns>
error_code insert_list_ready(OS_TCB* tcb)
{
    switch (tcb->status)
    {
    case TaskStatus_Default: {
    }
                           break;
    case TaskStatus_Running: {
    }
                           break;
    case TaskStatus_Ready: {
        return OS_insReady_task_is_ready;
    }
//                         break;
    case TaskStatus_Sleep: {
        //将tcb从休眠表中移出
        dlist_remove(&list_sleep, &tcb->node);
    }
                         break;
    case TaskStatus_Suspend: {
        //将tcb从阻塞表中移出
        dlist_remove(&list_suspend,   &tcb->node);
    }
                           break;
    case TaskStatus_Dead: {
        return OS_insReady_task_is_dead;
    }
//                        break;
    default: break;
    }

    tcb->status = TaskStatus_Ready;
    //下面将任务插进就绪表。任务优先级高的排前面，优先级低的排后面。保证高优先级的优先运行。
    //同优先级的，上次运行时间比较少的排前面，以便能快速执行的任务优先执行
    dlist_ins_orderly(&list_ready, &tcb->node);
    return OS_no_error;
}

/// <summary>
/// 将任务插入阻塞表
/// </summary>
/// <param name="tcb">任务。
/// 如果tcb是默认态，直接插入阻塞表。
/// 如果tcb是运行态，直接插入阻塞表。
/// 如果tcb是就绪态，先从就绪链表中移出节点，再插入阻塞表。
/// 如果tcb是挂起态，说明tcb已经在阻塞表了，直接退出。
/// 如果tcb是休眠态，先从休眠链表中移出节点，再插入阻塞表。
/// 如果tcb是终止态，直接退出。
/// </param>
/// <returns>错误码</returns>
error_code insert_list_suspend(OS_TCB* tcb)
{
    switch (tcb->status)
    {
    case TaskStatus_Default: {
        break;
    }
    case TaskStatus_Running: {
        break;
    }
    case TaskStatus_Ready: {
        //将tcb从就绪表中移出
        dlist_remove(&list_ready, &tcb->node);
        break;
    }
    case TaskStatus_Sleep: {
        //将tcb从休眠表中移出
        dlist_remove(&list_sleep, &tcb->node);
        break;
    }
    case TaskStatus_Suspend: {
        return OS_insSuspend_task_is_suspend;
//        break;
    }
    case TaskStatus_Dead: {
        return OS_insSuspend_task_is_dead;
//        break;
    }
    default: break;
    }

    //将任务插入到就阻塞表末尾。
    tcb->status = TaskStatus_Suspend;
    dlist_push_back(&list_suspend,   &tcb->node);
    return OS_no_error;
}

/// <summary>
/// 根据醒来时间的先后，将任务有序插入休眠表。
/// </summary>
/// <param name="tcb">任务。
/// 如果tcb是默认态，直接插入休眠表。
/// 如果tcb是运行态，直接插入休眠表。
/// 如果tcb是就绪态，先从就绪链表中移出节点，再插入休眠表。
/// 如果tcb是挂起态，直接退出，不允许挂起的任务睡觉。
/// 如果tcb是休眠态，先从休眠链表中移出节点，刷新唤醒的时间。以更长的唤醒时间为准，再插入休眠节点。
/// 如果tcb是终止态，直接退出。
/// </param>
/// <param name="ticks">休眠的时间</param>
/// <returns>错误码</returns>
error_code insert_list_sleep(OS_TCB* tcb, unt16 ticks) //
{
    switch (tcb->status)
    {
    case TaskStatus_Default: {
    }
                           break;
    case TaskStatus_Running: {
    }
                           break;
    case TaskStatus_Ready: {
        //将tcb从就绪表中移出
        dlist_remove(&list_ready, &tcb->node);
    }
                         break;
    case TaskStatus_Sleep: {
        //将tcb从休眠表中移出，刷新唤醒的时间。
        dlist_remove(&list_sleep, &tcb->node);
    }
                         break;
    case TaskStatus_Suspend: {
        return OS_insSleep_task_is_suspend;
    }
//                           break;
    case TaskStatus_Dead: {
        return OS_insSleep_task_is_dead;
    }
//                        break;
    default: break;
    }

    //下面进行延时。以大的timeWakeUp_ms为准。
    unt32 machineTime_ms = mcu_time_ms();
    if (tcb->timeWakeUp_ms < machineTime_ms) //如果唤醒时间在以前，说明已经醒着了。
    {
        tcb->timeWakeUp_ms = machineTime_ms + ticks;
    }
    else if (tcb->timeWakeUp_ms < machineTime_ms + ticks) {
        //如果新的醒来的时间，在现在醒来时间的后面，则用新的醒来时间。
        tcb->timeWakeUp_ms = machineTime_ms + ticks;
    }

    tcb->status = TaskStatus_Sleep;
    //对延时时间进行排序，从小到大。
    dlist_ins_orderly(&list_sleep, &tcb->node);
    return OS_no_error;
}


/// <summary>
/// 任务就只有下面几种操作：创建任务（初始化），挂起，恢复，休眠，修改优先级，退出任务。
/// os_开头的函数都是开放的。
/// insert_list_开头的函数主要考虑任务在链表之间会不会冲突，是os_开头函数的辅助函数。
/// </summary>

/// <summary>
/// 允许运行中动态更改任务的优先级。
/// </summary>
/// <param name="tcb">需要修改优先级的任务</param>
/// <param name="new_prio">新的优先级</param>
/// <returns>错误码</returns>
error_code os_task_change_prio(OS_TCB* tcb, unt8 new_prio)
{
    if (new_prio == OS_IDLE_TASK_PRIO)   //如果是空闲任务的优先级，返回优先级不合法警告
    {
        return (OS_changePrio_prio_is_invalid);
    }
    if (tcb == &idle_tcb) { //如果tcb是空闲任务的指针，则返回不合法警告
        return (OS_changePrio_task_is_idle);
    }

    //如果tcb是默认态，直接修改优先级。
    //如果tcb是就绪态，先从就绪链表中移出节点，修改优先级后再插回节点
    //如果tcb是运行态，直接修改优先级。
    //如果tcb是挂起态，直接修改优先级。
    //如果tcb是休眠态，直接修改优先级。
    //如果tcb是终止态，直接退出。

    switch (tcb->status)
    {
    case TaskStatus_Default: {
    }
                           break;
    case TaskStatus_Running: {
    }
                           break;
    case TaskStatus_Ready: {
        //将tcb从就绪表中移出
        dlist_remove(&list_ready, &tcb->node);
        tcb->priority = new_prio;
        //再次插入链表
        insert_list_ready(tcb);
        return OS_no_error;
    }
//                         break;
    case TaskStatus_Sleep: {
    }
                         break;
    case TaskStatus_Suspend: {
    }
                           break;
    case TaskStatus_Dead: {
        return OS_changePrio_task_is_dead;
    }
//                        break;
    default: break;
    }

    tcb->priority = new_prio;
    return OS_no_error;
}

/// <summary>
/// 调用此函数去挂起一个任务。如果tcb是null，挂起当前的任务。
/// </summary>
/// <param name="tcb">要挂起的任务。空闲任务不能被挂起</param>
/// <returns>错误码</returns>
error_code os_task_suspend(OS_TCB* tcb)
{
    if (tcb == NULL) {
        insert_list_suspend(currentRuning);
        return (OS_no_error);
    }
    if (tcb == &idle_tcb)  return (OS_task_suspend_IDLE);
    insert_list_suspend(tcb);
    return (OS_no_error);               
}

/// <summary>
/// 调用此函数以恢复先前挂起的任务，将挂起的任务插入就绪表
/// </summary>
/// <param name="tcb">请求恢复的任务</param>
/// <returns>错误码</returns>
error_code os_task_resume(OS_TCB* tcb)
{
    //只有被挂起来的任务可以恢复
    if (tcb->status != TaskStatus_Suspend) return OS_task_resume_taskNotSuspended;   
    insert_list_ready(tcb);  
    return (OS_no_error);
}

/// <summary>
/// 将任务进入休眠态。
/// 在任务函数运行中调用它来休眠，任务并不会立即休眠，而是等任务函数退出后再进入休眠状态。
/// </summary>
/// <param name="tcb">要休眠的任务。空闲任务不能休眠。</param>
/// <param name="ticks">任务休眠的时间。如果任务已经在休眠，则刷新休眠时间，以睡得久的时间为准</param>
/// <returns>错误码</returns>
error_code os_sleep_ms(OS_TCB* tcb, unt16 ticks)
{
    if (tcb == &idle_tcb)  //空闲任务不能休眠
        return (OS_sleep_idle);
    if (tcb == NULL) {
        tcb = currentRuning;
    }
    insert_list_sleep(tcb, ticks);
    return OS_no_error;
}

/// <summary>
/// 初始化任务的信息。
/// </summary>
/// <param name="tcb">任务</param>
void init_task_msg(OS_TCB* tcb)
{
    TCB_MSG* msg = &(tcb->msg);
    msg->machineTime_ms = 0;
    msg->callDelay_ms = 0;
    msg->callDelay_msCount = 0;
    msg->callTimes = 0;
    msg->callTimesCount = 0;
    msg->timeUsed_ms = 0;
    msg->timeUsed_msCount = 0;
}


/// <summary>
/// 创建任务。
/// </summary>
/// <param name="tcb">用户创建的任务地址。</param>
/// <param name="task">任务函数指针</param>
/// <param name="task_prio">任务优先级</param>
/// <param name="identity">任务id号</param>
/// <param name="timeInterval">任务执行间隔。注意：如果任务休眠的时间比执行间隔短，则休眠不会起效果。</param>
/// <returns>错误码</returns>
error_code os_task_create(OS_TCB* tcb, void (*task)(void), unt8 task_prio, unt8 identity, int timeInterval)
{
    if (tcb == NULL) {
        return (OS_cannot_create_new_task);  //如果分配节点出错，返回相应的错误。
    }
    if (timeInterval <= 0)timeInterval = 1; //任务至少每毫秒休息一次，以免它长时间占据CPU。
    //任务初始化
    init_task_msg(tcb);
    tcb->funcPoint = task;
    tcb->status = TaskStatus_Default;  //创建任务的时候都是默认状态。
    tcb->id = identity;
    tcb->timeUsed_ms = 0;
    tcb->timeWakeUp_ms = 0;
    tcb->timeInterval_ms = timeInterval;
    tcb->priority = task_prio;

    //将任务插入就绪链表
    insert_list_ready(tcb);
    return (OS_no_error);
}

/// <summary>
/// 退出任务
/// </summary>
/// <param name="tcb">退出的任务。如果tcb是null，则退出当前运行的任务</param>
void os_task_exit(OS_TCB* tcb)
{
    if (tcb == NULL) {
        tcb = currentRuning;
    }
    else if (tcb->status == TaskStatus_Ready)
    {
        //将tcb从就绪表中移出
        dlist_remove(&list_ready, &tcb->node);
    }
    else if (tcb->status == TaskStatus_Sleep)
    {
        //将tcb从休眠表中移出
        dlist_remove(&list_sleep, &tcb->node);
    }
    else if (tcb->status == TaskStatus_Suspend)
    {
        //将tcb从阻塞表中移出
        dlist_remove(&list_suspend,   &tcb->node);
    }
    tcb->status = TaskStatus_Dead;
}

/*************************************系统初始化代码*******************************************/

/// <summary>
/// 用户定义的空闲任务
/// </summary>
func user_idle_func = NULL; 
/// <summary>
/// 空闲任务的时间计数。以CPU_Refresh_Interval_ms为单位递增
/// </summary>

/// <summary>
/// 空闲任务执行函数。
/// </summary>
/// <param name=""></param>
void default_idle(void)
{
    //空闲任务，如果有用户定义的函数，就执行用户定义的函数。
    if (user_idle_func != NULL) {
        user_idle_func();
    }

#if (1)
    static unt32 idle_time_ms = 0;  
    if ((idle_time_ms + CPU_Refresh_Interval_ms) < mcu_time_ms()) {
        idle_time_ms += CPU_Refresh_Interval_ms;

        //下面的代码用于打印cpu的利用率等信息。
        int s = mcu_time_ms() / 1000;
        printfs("\r\n cuttent time:%d  s ", s);
        debug_print_Sleep_msg();
        debug_print_Ready_msg();
        debug_print_Suspend_msg();
    }
#endif 

    //执行完后，将空闲任务设为就绪态，插入就绪链表进行任务调度。       
    insert_list_ready(&idle_tcb);
}

/// <summary>
/// 用户定义空闲任务
/// </summary>
/// <param name="idle_func">用户定义的空闲任务</param>
void os_user_idle(func idle_func)
{
    user_idle_func = idle_func;
}

/// <summary>
/// 操作系统初始化。主要是初始化任务链表，创建空闲任务。
/// </summary>
/// <param name=""></param>
void os_init(void)
{
    dlist_init(&list_suspend,   NULL);
    dlist_init(&list_sleep, list_sleep_cmp);
    dlist_init(&list_ready, list_ready_cmp); 
    //创建空闲任务
    os_task_create(&idle_tcb, default_idle, OS_IDLE_TASK_PRIO, OS_IDLE_TASK_ID, -1);
}

/// <summary>
/// 更新就绪表。从休眠表中查找休眠完成的任务，将其插入就绪表。
/// 在任务调度前要执行这个函数。
/// </summary>
void renew_list_ready()
{
    DListNode* tcb_node;
    DListNode* tcb_node_prev;
    OS_TCB* tcb;
    if (list_sleep.count > 0) {
        tcb_node = list_sleep.tail;
        while (tcb_node != NULL) {
            tcb_node_prev = tcb_node->prev;   //先保存好tcb_prev，如果下面tcb插入了就绪表，就不能用tcb的prev寻找休眠表的元素了。
            tcb = container_of(tcb_node, OS_TCB, node);
            if (tcb->timeWakeUp_ms <= mcu_time_ms()) {
                //如果醒来的时间比当前的时间小，说明它睡过头了，应该醒来了
                insert_list_ready(tcb);
            }
            else {
                return;  //尾节点是最早唤醒的。遇到现在还没醒的，后面就不用看了。
            }
            tcb_node = tcb_node_prev;
        }
    }
}

/// <summary>
/// 进入任务更新任务的信息。
/// 在任务函数执行前调用这个函数
/// </summary>
/// <param name="tcb">任务</param>
/// <param name="mtime">当前的机器时间</param>
void come_in_Task(OS_TCB* tcb, unt32 mtime)
{
    if (tcb != NULL)
    {
        TCB_MSG* msg = &(tcb->msg);
        if ((msg->machineTime_ms + CPU_Refresh_Interval_ms) < mtime) {  //刷新一次信息。
            msg->timeUsed_ms = msg->timeUsed_msCount;
            msg->callDelay_ms = msg->callDelay_msCount;
            msg->callTimes = msg->callTimesCount;
            msg->machineTime_ms += CPU_Refresh_Interval_ms;
            msg->timeUsed_msCount = 0;
            msg->callDelay_msCount = 0;
            msg->callTimesCount = 0;
        }
        //更新任务调用次数，总延迟时间。
        msg->callDelay_msCount += (mtime - tcb->timeWakeUp_ms);
        msg->callTimesCount++;
    }
}

/// <summary>
/// 退出任务更新任务信息
/// 在任务函数结束后调用这个函数。
/// </summary>
/// <param name="tcb">任务</param>
/// <param name="mtime">当前的机器时间</param>
/// <param name="usedtime">执行任务函数使用的时间</param>
void come_out_Task(OS_TCB* tcb, unt32 mtime, unt16 usedtime)
{
    if (tcb != NULL)
    {
        TCB_MSG* msg = &(tcb->msg);
        tcb->timeUsed_ms = usedtime;
        if ((msg->machineTime_ms + CPU_Refresh_Interval_ms) < mtime) {  //刷新一次信息。
            msg->timeUsed_ms = msg->timeUsed_msCount;
            msg->callDelay_ms = msg->callDelay_msCount;
            msg->callTimes = msg->callTimesCount;
            msg->machineTime_ms += CPU_Refresh_Interval_ms;
            msg->timeUsed_msCount = 0;
            msg->callDelay_msCount = 0;
            msg->callTimesCount = 0;
        }
        //更新任务使用时间。
        msg->timeUsed_msCount += usedtime;
    }
}

/// <summary>
/// 48天有 4147200 000毫秒  unt32最大的数字是4294967295。
/// </summary>
#define ms_48Day 4147200000u       //u先声明这个变量是无符号的。

/// <summary>
/// 系统运行函数。一旦进入，就会等系统运行了ms_48Day后再退出。中间会执行任务调度，不断从就绪表中提取函数。
/// </summary>
void os_running()
{
    static OS_TCB* tcb;
    static unt32 tcbtime;
    while (mcu_time_ms() < ms_48Day)  //运行到48天将会退出系统运行。
    {

        renew_list_ready();//先更新就绪表

        //提取就绪表尾结点。链表从小到大排序，最后面的优先级最高。
        tcb = container_of(list_ready.tail, OS_TCB, node);
        dlist_pop_back(&list_ready);
        currentRuning = tcb;

        //这里判断当前任务有无异常。无异常才执行任务函数。如果有异常，就退出。        
        if (debug_currentRuning_iserror())break;   

        //要及时更改运行任务的状态。
        currentRuning->status = TaskStatus_Running;
        tcbtime = mcu_time_ms();
        //进入任务更新任务信息。
        come_in_Task(currentRuning, mcu_time_ms());
        //在执行任务前，先定下下次唤醒的时间，以免节点的任务没有定义。
        os_sleep_ms(currentRuning, currentRuning->timeInterval_ms);
        //执行节点函数
        currentRuning->funcPoint();
        //退出任务更新任务信息。
        come_out_Task(currentRuning, mcu_time_ms(), ((unt32)mcu_time_ms() - (unt32)tcbtime));
    }
}



//


